package com.sdgs.paas.sdk.core.jpa;

import java.lang.reflect.Field;
import java.util.Date;

import javax.persistence.EntityManager;
import javax.persistence.Id;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.data.querydsl.EntityPathResolver;
import org.springframework.data.querydsl.SimpleEntityPathResolver;

import com.querydsl.core.types.EntityPath;
import com.querydsl.core.types.dsl.BooleanPath;
import com.querydsl.core.types.dsl.DatePath;
import com.querydsl.core.types.dsl.NumberPath;
import com.querydsl.core.types.dsl.PathBuilder;
import com.querydsl.core.types.dsl.StringPath;
import com.querydsl.jpa.impl.JPAUpdateClause;
import com.sdgs.paas.sdk.core.PaasBaseException;
import static com.sdgs.paas.sdk.core.PaasResponseEnum.JPA_UNSUPPORT_ARG;

/**
 * Jpa存储库帮助类
 *
 * @author wjj
 *
 * @param <T>
 *            数据库表对象
 */

public class PaasJpaRepositoryHelperImpl implements IPaasJpaRepositoryHelper {

	private static final EntityPathResolver DEFAULT_ENTITY_PATH_RESOLVER = SimpleEntityPathResolver.INSTANCE;
	@Autowired
	private EntityManager em;

	@SuppressWarnings("unchecked")
	@Override
	public <T> Long updExcludNullField(T entity) throws IllegalArgumentException, IllegalAccessException {
		Class<T> cls = (Class<T>) entity.getClass();
		final EntityPath<T> path = DEFAULT_ENTITY_PATH_RESOLVER.createPath(cls);
		final PathBuilder<T> builder = new PathBuilder<T>(path.getType(), path.getMetadata());
		JPAUpdateClause upd = new JPAUpdateClause(em, path);
		Field[] fields = cls.getDeclaredFields();

		for (Field f : fields) {

			f.setAccessible(true);
			Id annoId = AnnotationUtils.findAnnotation(f, Id.class);
			Class<?> fcls = f.getType();
			String typename = fcls.getName();
			String fn = f.getName();
			// Type fgt = f.getGenericType();

			switch (typename) {
			case "java.lang.Integer":
			case "int":
				NumberPath<Integer> intId = builder.getNumber(fn, Integer.class);
				Integer intIdval = (Integer) f.get(entity);
				if (annoId != null) {
					upd.where(intId.eq((Integer) intIdval));
				} else if (intIdval != null) {
					upd.set(intId, intIdval);
				}
				break;
			case "java.lang.Double":
			case "double":
				NumberPath<Double> doubleId = builder.getNumber(fn, Double.class);
				Double doubleIdval = (Double) f.get(entity);
				if (annoId != null) {
					upd.where(doubleId.eq((Double) doubleIdval));
				} else if (doubleIdval != null) {
					upd.set(doubleId, doubleIdval);
				}

				break;
			// case "java.lang.Float":
			case "java.lang.Long":
			case "long":
				NumberPath<Long> longId = builder.getNumber(fn, Long.class);
				Long longIdval = (Long) f.get(entity);
				if (annoId != null) {
					upd.where(longId.eq((Long) longIdval));
				} else if (longIdval != null) {
					upd.set(longId, longIdval);
				}

				break;
			case "java.lang.Short":
			case "short":
				NumberPath<Short> shortId = builder.getNumber(fn, Short.class);
				Short shortIdval = (Short) f.get(entity);
				if (annoId != null) {
					upd.where(shortId.eq((Short) shortIdval));
				} else if (shortIdval != null) {
					upd.set(shortId, shortIdval);
				}

				break;
			// case "java.lang.Byte":
			case "java.lang.Boolean":
			case "boolean":
				BooleanPath booleanId = builder.getBoolean(fn);
				Boolean booleanIdval = (Boolean) f.get(entity);
				if (annoId != null) {
					upd.where(booleanId.eq((Boolean) booleanIdval));
				} else if (booleanIdval != null) {
					upd.set(booleanId, booleanIdval);
				}
				break;
			// case "java.lang.Character":
			case "java.lang.String":
				StringPath stringId = builder.getString(fn);
				String stringIdval = (String) f.get(entity);
				if (annoId != null) {
					upd.where(stringId.eq((String) stringIdval));
				} else if (stringIdval != null) {
					upd.set(stringId, stringIdval);
				}
				break;
			case "java.util.Date":
				DatePath<Date> dateId = builder.getDate(fn, Date.class);
				Date dateIdval = (Date) f.get(entity);
				if (annoId != null) {
					upd.where(dateId.eq((Date) dateIdval));
				} else if (dateIdval != null) {
					upd.set(dateId, dateIdval);
				}
				break;
			// case "byte":
			// case "char":
			// case "float":
			default:
				throw new PaasBaseException(JPA_UNSUPPORT_ARG.code(), String.format(JPA_UNSUPPORT_ARG.msg(), typename));

			}

		}

		return upd.execute();
	}

	public EntityManager getEm() {
		return em;
	}

	public void setEm(EntityManager em) {
		this.em = em;
	}

}
